import os, sys, time, subprocess, tempfile
################################################################################
################################################################################
def opentee( fn ):
    # http://stackoverflow.com/questions/616645/how-do-i-duplicate-sys-stdout-to-a-log-file-in-python
    sys.stdout = os.fdopen( sys.stdout.fileno(), 'w', 0 )
    #
    tee = subprocess.Popen([ 'tee', fn ], stdin=subprocess.PIPE )
    os.dup2( tee.stdin.fileno(), sys.stdout.fileno() )
    os.dup2( tee.stdin.fileno(), sys.stderr.fileno() )

################################################################################
################################################################################
def FileNameTimeStamp():
    theTime = time.localtime()
    yr  = '%04d' % ( theTime.tm_year )
    mon = '%02d' % ( theTime.tm_mon  )
    day = '%02d' % ( theTime.tm_mday )
    hr  = '%02d' % ( theTime.tm_hour )
    mt  = '%02d' % ( theTime.tm_min  )
    sec = '%02d' % ( theTime.tm_sec  )
    ymd = '_'.join([ yr, mon, day ])
    hms = '_'.join([ hr, mt,  sec ])
    return '__'.join([ ymd, hms ])

def PrintTimeStamp():
    theTime = time.localtime()
    yr  = '%04d' % ( theTime.tm_year )
    mon = '%02d' % ( theTime.tm_mon  )
    day = '%02d' % ( theTime.tm_mday )
    hr  = '%02d' % ( theTime.tm_hour )
    mt  = '%02d' % ( theTime.tm_min  )
    sec = '%02d' % ( theTime.tm_sec  )
    print '...', '/'.join( [yr, mon, day] ), ':'.join( [hr, mt, sec] )
    sys.stdout.flush()

def SystemWrapperPipelined( cmd, verbose = False, trial = False ):
    if verbose:
        PrintTimeStamp()
        print '... os.popen(', cmd, ')'
        sys.stdout.flush()
    if not trial:
        FH = os.popen( cmd )
        output = [ line.rstrip() for line in FH.readlines() ]
        FH.close()
        return output
    return []

def SystemWrapper( cmd, verbose = True, trial = False ):
    dt = 0
    if verbose:
        PrintTimeStamp()
        print '... os.system(', cmd, ')'
        sys.stdout.flush()
    if trial:
        status = 0
    else: 
        t0 = time.time()
        status = os.system( cmd )
        t1 = time.time()
        dt = t1 - t0
    assert status == 0
    if verbose:
        toks = cmd.split()
        ( cmdPath, rawCmd ) = os.path.split( toks[0] )
        if len( toks ) > 1: cmdstr = ' '.join([ rawCmd, toks[1] ])
        else:               cmdstr = rawCmd
        print '...', '%5.2f' % (dt) , 'seconds elapsed, finished:', cmdstr
        sys.stdout.flush()
    return dt

def TrySystemWrapper( cmd, verbose = True, trial = False ):
    try:
        SystemWrapper( cmd, verbose, trial )
    except:
        print '[warning] - TrySystemWrapper( cmd =', cmd, ', verbose =', verbose, ', trial = ', trial, ') failed'
    
def TrySystemWrapperPipelined( cmd, verbose = False, trial = False ):
    try:
        pipelines = SystemWrapperPipelined( cmd, verbose, trial )
        return pipelines
    except:
        return []

################################################################################
################################################################################
def ExtractProcMem( key ):
    lines = SystemWrapperPipelined( 'cat /proc/meminfo' )
    for line in lines:
        toks = line.split()
        if len( toks ):
            if toks[0].rstrip( ':' ) == key:
                memkb = int( toks[1] )
                assert toks[2] == 'kB'
                return 1024 * memkb
    return None

def TotalMemAvail():
    return ExtractProcMem( 'MemTotal' )

def MemFree():
    return ExtractProcMem( 'MemFree' )

################################################################################
################################################################################
def which( x ):
    path = os.getenv( 'PATH' )
    for p in path.split( os.path.pathsep ):
        p = os.path.join( p, x )
        if os.path.isfile( p ) and os.access( p ,os.X_OK ):
            return p
    return None

def makedirp( p ):
    if not os.path.exists( p ):
        os.makedirs( p )

def df( p ):
    """
    Returns the number of free bytes on the drive that ``p`` is on
    """
    # http://atlee.ca/blog/2008/02/23/getting-free-diskspace-in-python/
    s = os.statvfs( p )
    return s.f_bsize * s.f_bavail

def VerifyRoot():
    uid = os.getuid()
    if uid != 0:
        print 'must be root'
        sys.exit( -1 )

################################################################################
################################################################################
def ZestImgPathEnvVar():
    return 'ZEST_MEMIMAGE_PATH'

def ZestRoot():
    zrpkey = 'ZEST_ROOT_PATH'
    if zrpkey not in os.environ:
        p = os.path.abspath( '..' )
        return p
    else:
        return os.environ[ zrpkey ]

def RawImagePath():
    ipenvvar = ZestImgPathEnvVar()
    if ipenvvar not in os.environ:
        tmppath = tempfile.gettempdir()
        assert os.path.isdir( tmppath )
        return tmppath
    else:
        return os.environ[ ipenvvar ]

def NewImagePath():
    ipenvvar = ZestImgPathEnvVar()
    if ipenvvar not in os.environ:
        tmppath = tempfile.gettempdir()
        assert os.path.isdir( tmppath )
        sesh  = '-'.join([ 'zest', FileNameTimeStamp() ])
        ipath = os.path.join( tmppath, sesh )
        makedirp( ipath )
        cmd = ' '.join([ 'chmod', 'a+rw', ipath ])
        SystemWrapper( cmd, verbose = False, trial = False )
        return ipath
    else:
        return os.environ[ ipenvvar ]

